0
0
2
Cover image for How to Implement a Doubly Linked List in JavaScript 🙇‍♂️📖

How to Implement a Doubly Linked List in JavaScript 🙇‍♂️📖

Doubly Linked List

class LinkedListNode { // LinkedListNode class constructor(value, next = null, prev = null) { this.value = value; //actual value to store (num/string/bool/obj) this.next = next; //pointer to next node this.prev = prev; //pointer to prev node } toString(callback) { return callback ? callback(this.value) : `${this.value}` } } class DoublyLinkedList { constructor() { this.head = null; this.tail = null; this.length = 0; } prepend(value) { if(!this.head) { this.head = newNode; this.tail = newNode; this.length++; return this; } const newNode = new LinkedListNode(value, this.head); this.head.prev = newNode this.head = newNode; this.length++; return this; } append(value) { const newNode = new LinkedListNode(value); if(!this.head) { this.head = newNode; this.tail = newNode; this.length++; return this; } const currentTail = this.tail; currentTail.next = newNode; newNode.prev = this.tail; //tail is now the 2nd last this.tail = newNode; this.length++; return this; } delete(value) { if(!this.head) { //is linked list empty? return null; } let deletedNode = null; let nextNode; // Is the node to be deleted the head? if (this.head && this.head.value === value) { deletedNode = this.head; //set deletedNode to it. nextNode = this.head.next; this.head = nextNode; nextNode.prev = null; deletedHead.next = null; deletedHead.prev = null; this.length--; return deletedNode; //return the deleted node } let currentNode = this.head; if (currentNode !== null) { //check it isn't null while (currentNode.next) { //as long as the next node exists if (currentNode.next.value === value) { //check value deletedNode = currentNode.next; //update deletedNode nextNode = deletedNode.next; currentNode.next = currentNode.next.next; nextNode.prev = deletedNode.prev; deletedNode.next = null; deletedNode.prev = null; this.length--; ) } else { currentNode = currentNode.next; x } } } // Is the node to be deleted the tail? if (this.tail.value === value) { this.tail = currentNode; this.length--; } return deletedNode; //return the deleted node } deleteTail() { //(pop) removes last node (list's tail) //No nodes? if (!this.head) { return null; //or undefined } const deletedTail = this.tail; //tail to be deleted/returned if (this.head === this.tail) { this.head = null; this.tail = null; this.length = 0; return deletedTail; } this.tail = deletedTail.prev; deletedTail.prev = null; this.tail.next = null; this.length--; return deletedTail; } deleteHead() { //(shift) removes first node //No nodes? if (!this.head) { return null;// or undefined } //1 or more nodes? const deletedHead = this.head; //capture the value to //be returned if (this.head.next) { //next exists? More than 1 this.head = deletedHead.next; deletedHead.next = null; this.head.prev = null; this.length--; } else { this.head = null; this.tail = null; this.length = 0; } return deletedHead; } //locates first item that matches value //takes value to match and callback find({ value = undefined, callback = undefined }) { //No node? List empty! if (!this.head) { return null; //or undefined } //track current position in list. let currentNode = this.head; while (currentNode) { // If callback is specified then try to find node by callback. if (callback && callback(currentNode.value)) { return currentNode; //return found node } // If value is specified then try to compare by value.. if (value !== undefined && currentNode.value === value) { return currentNode; //return found node } currentNode = currentNode.next; //similar to i++ (move on to next) } return null; //didn't find? null! } //Retrieve a node by its position get(index) { //not possible => null if(index < 0 || index >= this.length) { return null; } let count, currentNode; //index closer to the beginning => start from head, move forward if(index <= this.length/2) { count = 0; currentNode = this.head; while(count != index) { currentNode = currentNode.next; //i++ count++; } } else { //index closer to the end => start from tail, move back counter = this.length - 1; currentNode = this.tail; while(count != index) { currentNode = currentNode.prev; count--; } } return currentNode; } //Change a node's value by its position set(index, value) { let foundNode = this.get(index); if(foundNode) { foundNode.value = value; return true; } return false; } //insert new node at a specific position insert(index, value) { if(index < 0 || index > this.length) { return false; } if(index === this.length) { //insert at end (tail) return !!this.append(value); } if(index === 0) {//insert at start (head) return !!this.prepend(value); } //insertion at any other position let prevNode = get(index - 1); let nextNode = prevNode.next; let newNode = new LinkedListNode(value, nextNode) nextNode.prev = newNode; newNode.prev = prevNode prevNode.next = newNode; this.length++; return true; } //reversing the list in place reverse() { //track our current position in the list //13 -> 27 -> 32 -> 71 let currentNode = this.head; //13 this.head = this.tail; this.tail = currentNode; let prevNode = null; let nextNode; while(currentNode) { nextNode = currentNode.next; //27 currentNode.next = prevNode; //13 -> null prevNode = currentNode; //13 currentNode = nextNode; //27 } currentNode.next = currentNode.next.next; } toArray() { const nodes = []; let currentNode = this.head; while (currentNode) { nodes.push(currentNode); currentNode = currentNode.next; } return nodes; } toString(callback) { return this.toArray().map(node => node.toString(callback)).toString() } }

Discussion (5 comments)

avatar
avatar
Louis Pham
Oct 20, 2024
noway
avatar

Emily Waters

Entrepreneur. Professional gamer. Zombie aficionado. Coffee nerd. Hardcore travel geek. 📖📚

Location

Vancouver, BC

Work

Freelance Software Engineer